home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Pascal / Applications / NIH Image 1.59 / 1.59 Source / Lut.p < prev    next >
Encoding:
Text File  |  1995-09-01  |  52.0 KB  |  2,207 lines  |  [TEXT/PJMM]

  1. unit Lut;
  2. {This file contains routines that deal with the video Look-Up Table(LUT).}
  3.  
  4. interface
  5.  
  6.     uses
  7.         Memory, QuickDraw, Packages, Menus, Events, Fonts, Scrap, ToolUtils, Resources, Palettes, Printing, ColorPicker, globals, Utilities, Graphics;
  8.  
  9.     function GetPseudoColorIndex: integer;
  10.     function isGrayScaleLUT: boolean;
  11.     procedure DoMouseDownInLUT (event: EventRecord);
  12.     procedure DoCopyColor;
  13.     procedure PasteColor;
  14.     procedure ShowRGBValues (index: integer);
  15.     procedure InvertPalette;
  16.     procedure FindPoints (var x1, y1, x2, y2: integer);
  17.     procedure UpdateMap;
  18.     procedure ResetGraymap;
  19.     procedure DrawMap;
  20.     procedure DoMouseDownInMap;
  21.     procedure EnableThresholding (level: integer);
  22.     procedure DisableThresholding;
  23.     procedure DrawLUT;
  24.     procedure UpdateLUT;
  25.     procedure LoadColorTable (theColorTable: CTabHandle);
  26.     function LoadCLUTResource (id: integer): boolean;
  27.     procedure GetLookupTable (var table: LookupTable);
  28.     procedure RedrawLUTWindow;
  29.     procedure DrawDensitySlice (OptionKey: boolean);
  30.     procedure SelectLutTool;
  31.     procedure EnableDensitySlice;
  32.     procedure SetupPseudocolor;
  33.     procedure DoImportLut (fname: str255; vnum: integer);
  34.     procedure OpenOldPalette (fname: str255; RefNum: integer);
  35.     procedure OpenNewPalette (fname: str255; RefNum: integer);
  36.     procedure OpenColorTable (fname: str255; RefNum: integer);
  37.     procedure ImportPalette (FileType: OSType; fname: str255; vnum: integer);
  38.     procedure GetColorTable (id: integer);
  39.     procedure GetLutResource (id: integer);
  40.     procedure DrawScale;
  41.     procedure MakeSpectrum;
  42.     function GetColorTableItem (ctab: ColorTableType): integer;
  43.     procedure SwitchColorTables (item: integer; update: boolean);
  44.     procedure InitPaletteHeader (var hdr: PaletteHeader);
  45.     procedure ResetMap;
  46.     procedure DoLutOptions;
  47.     function SetupMask: boolean;
  48.     procedure PutLineUsingMask (h, v, count: integer; var line: LineType);
  49.     procedure ApplyTable (var table: LookupTable);
  50.     procedure FixColors;
  51.  
  52.  
  53.  
  54. implementation
  55.  
  56.  
  57.     function GetPseudoColorIndex: integer;
  58.         var
  59.             index: integer;
  60.     begin
  61.         with info^ do begin
  62.                 index := trunc((nColors) * (ForegroundIndex - ColorStart) / (ColorEnd - ColorStart + 1));
  63.                 if index < 0 then
  64.                     index := 0;
  65.                 if index > (nColors - 1) then
  66.                     index := nColors - 1;
  67.                 GetPseudoColorIndex := index;
  68.             end;
  69.     end;
  70.  
  71.  
  72.     procedure UpdateLUT;
  73.         var
  74.             MaxStart, i, v, index, last: integer;
  75.             inc, sIndex: LongInt;
  76.     begin
  77.         with info^ do begin
  78.                 sIndex := 0;
  79.                 if ColorEnd > ColorStart then
  80.                     inc := nColors * 10000 div (ColorEnd - ColorStart)
  81.                 else
  82.                     inc := 2560000;
  83.                 if ColorStart < 0 then
  84.                     sIndex := -ColorStart * Inc
  85.                 else
  86.                     sIndex := 0;
  87.                 last := nColors - 1;
  88.                 for i := 0 to 255 do
  89.                     with cTable[i].rgb do begin
  90.                             if (i < ColorStart) or (i > ColorEnd) then begin
  91.                                     if i < ColorStart then
  92.                                         cTable[i].rgb := FillColor1
  93.                                     else
  94.                                         cTable[i].rgb := FillColor2;
  95.                                 end
  96.                             else begin
  97.                                     index := sIndex div 10000;
  98.                                     if index > last then
  99.                                         index := last;
  100.                                     Red := bsl(band(RedLUT[index],255), 8);
  101.                                     Green := bsl(band(GreenLUT[index],255), 8);
  102.                                     Blue := bsl(band(BlueLUT[index],255), 8);
  103.                                     sIndex := sIndex + inc;
  104.                                 end;
  105.                         end; {for}
  106.                 if ColorStart = ColorEnd then
  107.                     cTable[ColorStart].rgb := FillColor2
  108.                 else
  109.                     Thresholding := false;
  110.                 LoadLUT(cTable);
  111.                 IdentityFunction := false;
  112.             end;
  113.     end;
  114.  
  115.  
  116.     function GetVLoc: integer;
  117.         var
  118.             loc: point;
  119.             vloc: integer;
  120.     begin
  121.         GetMouse(loc);
  122.         vloc := loc.v;
  123.         if vloc > 255 then
  124.             vloc := 255;
  125.         if vloc <= 0 then
  126.             vloc := 0;
  127.         GetVLoc := vloc;
  128.     end;
  129.  
  130.  
  131.     procedure GetNewColor (var color: RGBColor);
  132.         var
  133.             where: point;
  134.             inRGBColor, OutRGBColor: RGBColor;
  135.     begin
  136.         inRGBColor := color;
  137.         outRGBColor := color;
  138.         where.h := 0;
  139.         where.v := 0;
  140.         InitCursor;
  141.         if GetColor(where, 'Pick a new color...', inRGBColor, outRGBColor) then
  142.             color := outRGBColor;
  143.     end;
  144.  
  145.  
  146.     procedure EditPseudoColors;
  147.         var
  148.             where: point;
  149.             inRGBColor, OutRGBColor: RGBColor;
  150.             index, mloc: integer;
  151.     begin
  152.         SetupLUTUndo;
  153.         with info^ do begin
  154.                 SetPort(LUTWindow);
  155.                 mloc := getvloc;
  156.                 if mloc < ColorStart then begin
  157.                         GetNewColor(FillColor1);
  158.                         UpdateLUT;
  159.                         exit(EditPseudoColors);
  160.                     end;
  161.                 if mloc > ColorEnd then begin
  162.                         GetNewColor(FillColor2);
  163.                         UpdateLUT;
  164.                         exit(EditPseudoColors);
  165.                     end;
  166.                 index := GetPseudoColorIndex;
  167.                 with inRGBColor do begin
  168.                         red := bsl(RedLUT[index], 8);
  169.                         green := bsl(GreenLUT[index], 8);
  170.                         blue := bsl(BlueLUT[index], 8);
  171.                     end;
  172.                 outRGBColor := inRGBColor;
  173.                 where.h := 0;
  174.                 where.v := 0;
  175.                 InitCursor;
  176.                 if GetColor(where, 'Pick a color, any color...', inRGBColor, outRGBColor) then begin
  177.                         with outRGBColor do begin
  178.                                 RedLUT[index] := bsr(red, 8);
  179.                                 GreenLUT[index] := bsr(green, 8);
  180.                                 BlueLUT[index] := bsr(blue, 8);
  181.                             end;
  182.                         changes := true;
  183.                     end;
  184.                 ColorTable := CustomTable;
  185.                 LutMode := PseudoColor;
  186.                 UpdateLUT;
  187.             end; {with}
  188.     end;
  189.  
  190.  
  191.     function EditSliceColor: boolean;
  192.         var
  193.             where: point;
  194.             inRGBColor, OutRGBColor: RGBColor;
  195.             vloc: integer;
  196.     begin
  197.         SetPort(LUTWindow);
  198.         vloc := getvloc;
  199.         if (vloc >= SliceStart) and (vloc <= SliceEnd) then begin
  200.                 GetNewColor(SliceColor);
  201.                 DrawDensitySlice(false);
  202.                 EditSliceColor := true
  203.             end
  204.         else
  205.             EditSliceColor := false;
  206.     end;
  207.  
  208.  
  209.     procedure ShowLUTValues (tStart, tEnd: integer);
  210.         var
  211.             tPort: GrafPtr;
  212.             value: extended;
  213.             range, NewMin, NewMax: LongInt;
  214.     begin
  215.         with info^ do begin
  216.                 GetPort(tPort);
  217.                 SetPort(InfoWindow);
  218.                 TextSize(9);
  219.                 TextFont(Monaco);
  220.                 TextMode(SrcCopy);
  221.                 MoveTo(xValueLoc, InfoVStart);
  222.                 if DataType <> EightBits then begin
  223.                         range := CurrentMax - CurrentMin;
  224.                         if tEnd < 255 then
  225.                             NewMin := CurrentMin + round(((255 - tEnd) / 255.0) * range)
  226.                         else
  227.                             NewMin := CurrentMin;
  228.                         DrawLong(NewMin);
  229.                         DrawString('    ');
  230.                         MoveTo(xValueLoc, InfoVStart + 10);
  231.                         if tStart > 0 then
  232.                             NewMax := CurrentMax - round((tStart / 255.0) * range)
  233.                         else
  234.                             NewMax := CurrentMax;
  235.                         DrawLong(NewMax);
  236.                         DrawString('    ');
  237.                         SetPort(tPort);
  238.                         exit(ShowLUTValues);
  239.                     end;
  240.                 if fit <> uncalibrated then begin
  241.                         if tStart >= 0 then
  242.                             value := cvalue[tStart]
  243.                         else
  244.                             value := cvalue[0];
  245.                         DrawReal(value, 5, 2);
  246.                         DrawString(' (');
  247.                         DrawReal(tStart, 3, 0);
  248.                         DrawString(')');
  249.                     end
  250.                 else
  251.                     DrawReal(tStart, 3, 0);
  252.                 DrawString('    ');
  253.                 MoveTo(xValueLoc, InfoVStart + 10);
  254.                 if fit <> uncalibrated then begin
  255.                         if tEnd <= 255 then
  256.                             value := cvalue[tEnd]
  257.                         else
  258.                             value := cvalue[255];
  259.                         DrawReal(value, 5, 2);
  260.                         DrawString(' (');
  261.                         DrawReal(tEnd, 3, 0);
  262.                         DrawString(')');
  263.                     end
  264.                 else
  265.                     DrawReal(tEnd, 3, 0);
  266.                 DrawString('    ');
  267.                 SetPort(tPort);
  268.             end;
  269.     end;
  270.  
  271.  
  272.     procedure ShowRGBValues (index: integer);
  273.         var
  274.             tPort: GrafPtr;
  275.             vloc: integer;
  276.     begin
  277.         with info^ do begin
  278.                 GetPort(tPort);
  279.                 SetPort(InfoWindow);
  280.                 TextSize(9);
  281.                 TextFont(Monaco);
  282.                 TextMode(SrcCopy);
  283.                 vloc := InfoVStart;
  284.                 MoveTo(xValueLoc, vloc);
  285.                 DrawLong(index);
  286.                 DrawString('    ');
  287.                 if Info^.fit <> uncalibrated then begin
  288.                         vloc := vloc + 10;
  289.                         MoveTo(xValueLoc, vloc);
  290.                         DrawReal(cvalue[index], 1, precision);
  291.                         DrawString('    ');
  292.                     end;
  293.                 vloc := vloc + 10;
  294.                 MoveTo(xValueLoc, vloc);
  295.                 DrawRGB(index);
  296.                 DrawString('    ');
  297.                 SetPort(tPort);
  298.             end;
  299.     end;
  300.  
  301.  
  302.     procedure FindPoints (var x1, y1, x2, y2: integer);
  303.     begin
  304.         with info^ do begin
  305.                 if ColorStart >= 0 then begin
  306.                         x1 := ColorStart;
  307.                         y1 := 0;
  308.                     end
  309.                 else begin
  310.                         x1 := 0;
  311.                         if ColorEnd > ColorStart then
  312.                             y1 := -ColorStart * 255 div (ColorEnd - ColorStart)
  313.                         else
  314.                             y1 := 0;
  315.                     end;
  316.                 if ColorEnd <= 255 then begin
  317.                         x2 := ColorEnd;
  318.                         y2 := 255;
  319.                     end
  320.                 else begin
  321.                         x2 := 255;
  322.                         if ColorEnd > ColorStart then
  323.                             y2 := 255 * (255 - ColorStart) div (ColorEnd - ColorStart)
  324.                         else
  325.                             y2 := 255;
  326.                     end;
  327.             end;
  328.     end;
  329.  
  330.  
  331.     procedure UpdateMap;
  332.         var
  333.             r: rect;
  334.             x, y, i, h1, h2, h3, v1, v2, v3, dx, dy: integer;
  335.             xcenter, ycenter, brightness, islope, thumb: integer;
  336.             width, max: integer;
  337.             table: LookupTable;
  338.             hrect: rect;
  339.             slope: extended;
  340.             area, value, sum: LongInt;
  341.             p1x, p1y, p2x, p2y: integer;
  342.     begin
  343.         with info^ do begin
  344.                 FindPoints(p1x, p1y, p2x, p2y);
  345.                 SetPort(MapWindow);
  346.                 PenNormal;
  347.                 EraseRect(MapRect2);
  348.                 FrameRect(MapRect1);
  349.                 if LutMode = CustomGrayscale then begin
  350.                         GetLookupTable(table);
  351.                         MoveTo(gmRectLeft, gmRectBottom - 1);
  352.                         for i := 0 to 63 do begin
  353.                                 x := gmRectLeft + i;
  354.                                 y := gmRectBottom - table[i * 4] div 4 - 1;
  355.                                 LineTo(x, y);
  356.                             end;
  357.                         EraseRect(gmSlide1i);
  358.                         EraseRect(gmSlide2i);
  359.                         exit(UpdateMap);
  360.                     end;
  361.                 h1 := gmRectLeft + p1x div 4;
  362.                 v1 := gmRectBottom - 1 - (p1y div 4);
  363.                 h2 := gmRectLeft + p2x div 4;
  364.                 v2 := gmRectBottom - 1 - (p2y div 4);
  365.                 MoveTo(gmRectLeft, gmRectBottom - 1);
  366.                 LineTo(h1, v1);
  367.                 LineTo(h2, v2);
  368.                 LineTo(gmRectRight - 1, gmRectTop);
  369.                 SetRect(hrect, h1 - 1, v1 - 1, h1 + 2, v1 + 2);
  370.                 PaintRect(hrect); {First handle}
  371.                 SetRect(hrect, h2 - 1, v2 - 1, h2 + 2, v2 + 2);
  372.                 PaintRect(hrect); {Last handle}
  373.                 dx := p2x - p1x;
  374.                 dy := p2y - p1y;
  375.                 xcenter := p1x + dx div 2;
  376.                 ycenter := p1y + dy div 2;
  377.                 h3 := gmRectLeft + xcenter div 4;
  378.                 v3 := gmRectBottom - 1 - (ycenter div 4);
  379.                 SetRect(hrect, h3 - 1, v3 - 1, h3 + 2, v3 + 2);
  380.                 PaintRect(hrect); {Center handle}
  381.                 thumb := gmSlideHeight - 2;
  382.                 max := gmSlideWidth - thumb - 2;
  383.                 width := ColorEnd - ColorStart;
  384.                 brightness := trunc(max * ((ColorStart + width) / (width + 255)));
  385.                 with gmSlide1 do
  386.                     SetRect(hrect, left + brightness + 1, top + 1, left + brightness + thumb + 1, top + thumb + 1);
  387.                 EraseRect(gmSlide1i);
  388.                 PaintRect(hrect);  {Thumb for contrast control}
  389.                 if dx <> 0 then
  390.                     slope := dy / dx
  391.                 else
  392.                     slope := 1000.0;
  393.                 if slope > 1.0 then begin
  394.                         if dy <> 0 then
  395.                             slope := 2.0 - dx / dy
  396.                         else
  397.                             slope := 2.0;
  398.                     end;
  399.                 islope := trunc(slope * 0.5 * (gmSlideWidth - thumb - 2.0));
  400.                 with gmSlide2 do
  401.                     SetRect(hrect, left + islope + 1, top + 1, left + islope + thumb + 1, top + thumb + 1);
  402.                 EraseRect(gmSlide2i);
  403.                 PaintRect(hrect);  {Thumb for contrast control}
  404.                 if ScreenDepth <> 8 then begin
  405.                         if ScreenDepth > 2 then
  406.                             DrawLut;
  407.                         UpdatePicWindow;
  408.                     end;
  409.             end;
  410.     end;
  411.  
  412.  
  413.     procedure UpdateThreshold;
  414.         var
  415.             level: integer;
  416.     begin
  417.         DrawLabels('Thresh:', '', '');
  418.         ShowMessage('');
  419.         with info^ do
  420.             repeat
  421.                 SetPort(LUTWindow);
  422.                 level := GetVLoc;
  423.                 if level <= 255 then begin
  424.                         ColorStart := level;
  425.                         ColorEnd := level;
  426.                         UpdateLUT;
  427.                         UpdateMap;
  428.                     end;
  429.                 Show1Value(level, NoValue);
  430.             until not Button;
  431.     end;
  432.  
  433.  
  434.     procedure UpdateDensitySlice;
  435.         var
  436.             mloc, saveloc, width, delta: integer;
  437.             adjust: (lower, upper, both);
  438.     begin
  439.         DrawLabels('Lower:', 'Upper:', '');
  440.         SetPort(LUTWindow);
  441.         mloc := getvloc;
  442.         saveloc := mloc;
  443.         width := SliceEnd - SliceStart + 1;
  444.         adjust := lower;
  445.         if mloc > (SliceStart + width div 4) then
  446.             adjust := both;
  447.         if mloc > (SliceEnd - width div 4) then
  448.             adjust := upper;
  449.         if (SliceStart = SliceEnd) and (abs(mloc - SliceStart) <= 2) and (SliceStart > 1) and (SliceEnd < 254) then
  450.             adjust := both;
  451.         while button do begin
  452.                 width := SliceEnd - SliceStart + 1;
  453.                 mloc := getvloc;
  454.                 delta := mloc - saveloc;
  455.                 saveloc := mloc;
  456.                 case adjust of
  457.                     lower:  begin
  458.                             SliceStart := mloc;
  459.                             if SliceStart < 1 then
  460.                                 SliceStart := 1;
  461.                             if SliceStart > SliceEnd then
  462.                                 SliceStart := SliceEnd;
  463.                         end;
  464.                     upper:  begin
  465.                             SliceEnd := mloc;
  466.                             if SliceEnd > 254 then
  467.                                 SliceEnd := 254;
  468.                             if SliceEnd < SliceStart then
  469.                                 SliceEnd := SliceStart;
  470.                         end;
  471.                     both:  begin
  472.                             if mloc <= 1 then begin
  473.                                     SliceStart := 1;
  474.                                     SliceEnd := width;
  475.                                 end
  476.                             else if mloc >= 254 then begin
  477.                                     SliceEnd := 254;
  478.                                     SliceStart := 254 - width + 1;
  479.                                 end
  480.                             else if ((SliceStart + delta) >= 1) and ((SliceEnd + delta) <= 254) then begin
  481.                                     SliceStart := SliceStart + delta;
  482.                                     SliceEnd := SliceEnd + delta;
  483.                                 end;
  484.                         end;
  485.                 end; {case}
  486.                 DrawDensitySlice(OptionKeyDown);
  487.                 ShowLUTValues(SliceStart, SliceEnd);
  488.             end; {while}
  489.         DrawDensitySlice(false)
  490.     end;
  491.  
  492.  
  493.     procedure EditExtraColors (entry: integer);
  494.         var
  495.             where: point;
  496.             inRGBColor, OutRGBColor: RGBColor;
  497.     begin
  498.         if (entry <> WhiteIndex) and (entry <> BlackIndex) then begin
  499.                 inRGBColor := ExtraColors[entry];
  500.                 outRGBColor := inRGBColor;
  501.                 where.h := 0;
  502.                 where.v := 0;
  503.                 InitCursor;
  504.                 if GetColor(where, 'Pick a color, any color...', inRGBColor, outRGBColor) then
  505.                     with info^ do begin
  506.                             ExtraColors[entry] := OutRGBColor;
  507.                             changes := true;
  508.                             LoadLUT(cTable);
  509.                         end
  510.             end
  511.         else
  512.             PutError('Sorry, but you can not edit white or black.');
  513.     end;
  514.  
  515.  
  516.     function GetColorFromLUT (DoubleClick: boolean): integer;
  517.         var
  518.             mloc, color, i: integer;
  519.             loc: point;
  520.     begin
  521.         SetPort(LUTWindow);
  522.         GetMouse(loc);
  523.         if loc.v > 255 then begin
  524.                 color := 0;
  525.                 for i := 1 to nExtraColors + 2 do
  526.                     if PtInRect(loc, ExtraColorsRect[i]) then
  527.                         Color := ExtraColorsEntry[i];
  528.                 if DoubleClick then
  529.                     EditExtraColors(color);
  530.                 GetColorFromLUT := color;
  531.             end
  532.         else
  533.             GetColorFromLUT := loc.v;
  534.     end;
  535.  
  536.  
  537.     function isGrayScaleLUT: boolean;
  538.         var
  539.             i: integer;
  540.             GrayScaleLUT: boolean;
  541.     begin
  542.         with info^ do begin
  543.                 GrayscaleLUT := true;
  544.                 i := 0;
  545.                 repeat
  546.                     with cTable[i].rgb do
  547.                         GrayscaleLUT := GrayscaleLUT and (red = green) and (green = blue);
  548.                     i := i + 1;
  549.                 until (i = 256) or not GrayscaleLUT;
  550.                 isGrayScaleLUT := GrayScaleLUT;
  551.             end;
  552.     end;
  553.  
  554.  
  555.     procedure SetupPseudocolor;
  556.         var
  557.             i: integer;
  558.     begin
  559.         with info^ do begin
  560.                 DisableDensitySlice;
  561.                 Thresholding := false;
  562.                 for i := 1 to 254 do
  563.                     with cTable[i].rgb do begin
  564.                             RedLUT[i] := band(bsr(red, 8), 255);
  565.                             GreenLUT[i] := band(bsr(green, 8), 255);
  566.                             BlueLUT[i] := band(bsr(blue, 8), 255);
  567.                         end;
  568.                 RedLUT[0] := RedLUT[1];
  569.                 GreenLUT[0] := GreenLUT[1];
  570.                 BlueLUT[0] := BlueLUT[1];
  571.                 RedLUT[255] := RedLUT[254];
  572.                 GreenLUT[255] := GreenLUT[254];
  573.                 BlueLUT[255] := BlueLUT[254];
  574.                 nColors := 256;
  575.                 ColorStart := 0;
  576.                 ColorEnd := 255;
  577.                 FillColor1 := ctable[1].rgb;
  578.                 FillColor2 := ctable[254].rgb;
  579.                 InvertedColorTable := false;
  580.             end;
  581.     end;
  582.  
  583.  
  584.     procedure ShowLabels;
  585.     begin
  586.         with info^ do
  587.             if DataType <> EightBits then
  588.                 DrawLabels('Min:', 'Max:', '')
  589.             else
  590.                 DrawLabels('Lower:', 'Upper:', '');
  591.     end;
  592.  
  593.  
  594.     procedure AdjustLUT;
  595.         const
  596.             MinWidth = 8;
  597.         var
  598.             mloc, saveloc, width, delta, cstart, cend: integer;
  599.             adjust: (lower, upper, both);
  600.             loc: point;
  601.     begin
  602.         with info^ do begin
  603.                 SetPort(LUTWindow);
  604.                 SetupLutUndo;
  605.                 ShowLabels;
  606.                 mloc := getvloc;
  607.                 saveloc := mloc;
  608.                 cstart := ColorStart;
  609.                 if cstart < 0 then
  610.                     cstart := 0;
  611.                 cend := ColorEnd;
  612.                 if cend > 255 then
  613.                     cend := 255;
  614.                 width := cend - cstart + 1;
  615.                 adjust := lower;
  616.                 if mloc > (cstart + width div 4) then
  617.                     adjust := both;
  618.                 if mloc > (cend - width div 4) then
  619.                     adjust := upper;
  620.                 while button do begin
  621.                         SetPort(LUTWindow);
  622.                         GetMouse(loc);
  623.                         mloc := loc.v;
  624.                         delta := mloc - saveloc;
  625.                         saveloc := mloc;
  626.                         case adjust of
  627.                             lower:  begin
  628.                                     ColorStart := mloc;
  629.                                     cend := ColorEnd;
  630.                                     if cend > 255 then
  631.                                         cend := 255;
  632.                                     if ColorStart > (cend - MinWidth) then
  633.                                         ColorStart := cend - MinWidth;
  634.                                 end;
  635.                             upper:  begin
  636.                                     ColorEnd := mloc;
  637.                                     cstart := ColorStart;
  638.                                     if cstart < 0 then
  639.                                         cstart := 0;
  640.                                     if ColorEnd < (cstart + MinWidth) then
  641.                                         ColorEnd := cstart + MinWidth;
  642.                                 end;
  643.                             both: 
  644.                                 if (mloc >= 0) and (mloc <= 255) then begin
  645.                                         ColorStart := ColorStart + delta;
  646.                                         ColorEnd := ColorEnd + delta;
  647.                                     end;
  648.                         end;
  649.                         UpdateLUT;
  650.                         UpdateMap;
  651.                         ShowLUTValues(ColorStart, ColorEnd);
  652.                     end;
  653.             end; {with info}
  654.     end;
  655.  
  656.  
  657.     procedure RotateLUT;
  658.         var
  659.             vstart, i, j, delta: integer;
  660.             loc: point;
  661.             TempTable: MyCSpecArray;
  662.     begin
  663.         with info^ do begin
  664.                 SetPort(LUTWindow);
  665.                 GetMouse(loc);
  666.                 vstart := loc.v;
  667.                 repeat
  668.                     GetMouse(loc);
  669.                     delta := vstart - loc.v;
  670.                     for i := 1 to 254 do begin {0 is resevred for white and 255 for black}
  671.                             j := i + delta;
  672.                             if j > 254 then
  673.                                 j := j - 254;
  674.                             if j > 254 then
  675.                                 j := 254;
  676.                             if j < 1 then
  677.                                 j := j + 254;
  678.                             if j < 1 then
  679.                                 j := 1;
  680.                             TempTable[i] := cTable[j]
  681.                         end;
  682.                     cTable := TempTable;
  683.                     LoadLUT(cTable);
  684.                     vstart := loc.v;
  685.                 until not button;
  686.                 SetupPseudocolor;
  687.                 ColorTable := CustomTable;
  688.             end;
  689.     end;
  690.  
  691.  
  692.     procedure DoMouseDownInLUT (event: EventRecord);
  693.         var
  694.             color: integer;
  695.             DoubleClick: boolean;
  696.     begin
  697.         with info^ do begin
  698.                 if CurrentTool = PickerTool then
  699.                     DoubleClick := (TickCount - LutTime) < GetDblTime
  700.                 else
  701.                     DoubleClick := false;
  702.                 LutTime := TickCount;
  703.                 if (CurrentTool <> LutTool) and (CurrentTool <> Wand) then begin
  704.                         color := GetColorFromLUT(DoubleClick);
  705.                         if (CurrentTool = eraser) or OptionKeyDown then
  706.                             SetBackgroundColor(color)
  707.                         else
  708.                             SetForegroundColor(color);
  709.                         if not DoubleClick then
  710.                             exit(DoMouseDownInLUT);
  711.                     end;
  712.                 if Thresholding then begin
  713.                         UpdateThreshold;
  714.                         exit(DoMouseDownInLUT)
  715.                     end;
  716.                 if DoubleClick then begin
  717.                         if DensitySlicing and (CurrentTool = PickerTool) then begin
  718.                                 if EditSliceColor then
  719.                                     exit(DoMouseDownInLUT);
  720.                             end;
  721.                         if CurrentTool = PickerTool then begin
  722.                                 EditPseudoColors;
  723.                                 exit(DoMouseDownInLUT)
  724.                             end;
  725.                     end; {if DoubleClick}
  726.                 if ((CurrentTool = LutTool) or (CurrentTool = Wand)) and DensitySlicing then begin
  727.                         UpdateDensitySlice;
  728.                         exit(DoMouseDownInLUT);
  729.                     end;
  730.                 if OptionKeyDown then
  731.                     RotateLUT
  732.                 else
  733.                     AdjustLUT;
  734.             end; {with}
  735.     end;
  736.  
  737.  
  738.     procedure DoCopyColor;
  739.     begin
  740.         with info^ do begin
  741.                 if ForegroundIndex = WhiteIndex then begin
  742.                         ClipboardColor := WhiteRGB;
  743.                         exit(DoCopyColor);
  744.                     end;
  745.                 if ForegroundIndex = BlackIndex then begin
  746.                         ClipboardColor := BlackRGB;
  747.                         exit(DoCopyColor);
  748.                     end;
  749.                 with cTable[ForegroundIndex].rgb do begin
  750.                         ClipboardColor.red := red;
  751.                         ClipboardColor.green := green;
  752.                         ClipboardColor.blue := blue;
  753.                     end;
  754.                 WhatsOnClip := AColor;
  755.                 ClipTextInBuffer := false;
  756.             end;
  757.     end;
  758.  
  759.  
  760.     procedure PasteColor;
  761.         var
  762.             CurrentColorIndex: integer;
  763.     begin
  764.         with info^ do begin
  765.                 if CurrentTool = PickerTool then begin
  766.                         if ForegroundIndex < ColorStart then begin
  767.                                 FillColor1 := ClipboardColor;
  768.                                 UpdateLUT;
  769.                                 exit(PasteColor);
  770.                             end;
  771.                         if ForegroundIndex > ColorEnd then begin
  772.                                 FillColor2 := ClipboardColor;
  773.                                 UpdateLUT;
  774.                                 exit(PasteColor);
  775.                             end;
  776.                         CurrentColorIndex := GetPseudoColorIndex;
  777.                         with ClipboardColor do begin
  778.                                 RedLUT[CurrentColorIndex] := bsr(red, 8);
  779.                                 GreenLUT[CurrentColorIndex] := bsr(green, 8);
  780.                                 BlueLUT[CurrentColorIndex] := bsr(blue, 8);
  781.                             end;
  782.                         ColorTable := CustomTable;
  783.                         UpdateLUT;
  784.                     end
  785.                 else
  786.                     beep;
  787.             end;
  788.     end;
  789.  
  790.  
  791.     procedure InvertPalette;
  792.         var
  793.             TempRed, TempGreen, TempBlue: LutArray;
  794.             i, LastColor: integer;
  795.             TempTable: MyCSpecArray;
  796.             TempFill: rgbColor;
  797.     begin
  798.         DisableDensitySlice;
  799.         DisableThresholding;
  800.         with info^ do begin
  801.                 TempRed := RedLUT;
  802.                 TempGreen := GreenLUT;
  803.                 TempBlue := BlueLUT;
  804.                 LastColor := ncolors - 1;
  805.                 for i := 0 to LastColor do begin
  806.                         RedLUT[i] := TempRed[LastColor - i];
  807.                         GreenLUT[i] := TempGreen[LastColor - i];
  808.                         BlueLUT[i] := TempBlue[LastColor - i];
  809.                     end;
  810.                 TempFill := FillColor1;
  811.                 FillColor1 := FillColor2;
  812.                 FillColor2 := TempFill;
  813.                 InvertedColorTable := not InvertedColorTable;
  814.                 IdentityFunction := false;
  815.             end;
  816.     end;
  817.  
  818.  
  819.     procedure DrawMap;
  820.         var
  821.             x, y, i: integer;
  822.             table: LookupTable;
  823.     begin
  824.         SetPort(MapWindow);
  825.         PenNormal;
  826.         TextFont(Geneva);
  827.         TextSize(9);
  828.         with gmSlide1 do
  829.             MoveTo(left - 6, bottom);
  830.         DrawChar('B');
  831.         with gmSlide2 do
  832.             MoveTo(left - 6, bottom);
  833.         DrawChar('C');
  834.         FrameRect(gmSlide1);
  835.         FrameRect(gmSlide2);
  836.         FrameRect(gmIcon1);
  837.         FrameRect(gmIcon2);
  838.         with gmIcon1 do begin
  839.                 MoveTo(left, top + 10);
  840.                 LineTo(left + 5, top + 10);
  841.                 LineTo(left + 12, top + 3);
  842.                 LineTo(left + gmIconWidth - 1, top + 3);
  843.             end;
  844.         with gmIcon2 do begin
  845.                 MoveTo(left, top + 10);
  846.                 LineTo(left + gmIconWidth div 2, top + 10);
  847.                 LineTo(left + gmIconWidth div 2, top + 3);
  848.                 LineTo(left + gmIconWidth - 1, top + 3);
  849.             end;
  850.         UpdateMap;
  851.         GrayMapReady := true;
  852.     end;
  853.  
  854.  
  855.     procedure ResetGrayMap;
  856.         var
  857.             i: integer;
  858.     begin
  859.         with info^ do begin
  860.                 DisableDensitySlice;
  861.                 for i := 0 to 255 do begin
  862.                         RedLut[i] := 255 - i;
  863.                         GreenLut[i] := 255 - i;
  864.                         BlueLut[i] := 255 - i;
  865.                     end;
  866.                 FillColor1 := WhiteRGB;
  867.                 FillColor2 := BlackRGB;
  868.                 ColorStart := 0;
  869.                 ColorEnd := 255;
  870.                 nColors := 256;
  871.                 ColorTable := CustomTable;
  872.                 LUTMode := Grayscale;
  873.                 UpdateLUT;
  874.                 if GrayMapReady then
  875.                     UpdateMap;
  876.                 IdentityFunction := true;
  877.                 InvertedColorTable := false;
  878.             end;
  879.     end;
  880.  
  881.  
  882.     procedure AdjustBrightness;
  883.         var
  884.             loc, max, thumb, xcenter, ycenter, width: integer;
  885.             p: point;
  886.     begin
  887.         with info^ do begin
  888.                 thumb := gmSlideHeight - 2;
  889.                 max := gmSlideWidth - thumb - 2;
  890.                 width := ColorEnd - ColorStart;
  891.                 ShowLabels;
  892.                 repeat
  893.                     GetMouse(p);
  894.                     loc := p.h - gmSlide1.left - 2;
  895.                     if loc < 0 then
  896.                         loc := 0;
  897.                     if loc > max then
  898.                         loc := max;
  899.                     ColorStart := -width + round((width + 255) * (loc / max));
  900.                     ColorEnd := ColorStart + width;
  901.                     UpdateLUT;
  902.                     UpdateMap;
  903.                     ShowLUTValues(ColorStart, ColorEnd);
  904.                 until not button;
  905.                 IdentityFunction := false;
  906.             end; {with}
  907.     end;
  908.  
  909.  
  910.     procedure AdjustContrast;
  911.         var
  912.             p: point;
  913.             loc, max, HalfMax, thumb: integer;
  914.             slope, center: extended;
  915.     begin
  916.         with info^ do begin
  917.                 thumb := gmSlideHeight - 2;
  918.                 max := gmSlideWidth - thumb - 2;
  919.                 HalfMax := max div 2;
  920.                 center := ColorStart + (ColorEnd - ColorStart) / 2.0;
  921.                 ShowLabels;
  922.                 repeat
  923.                     GetMouse(p);
  924.                     loc := p.h - gmSlide2.left - 2;
  925.                     if loc < 0 then
  926.                         loc := 0;
  927.                     if loc > max then
  928.                         loc := max;
  929.                     if loc <= HalfMax then
  930.                         slope := loc / HalfMax
  931.                     else if loc < max then
  932.                         slope := HalfMax / (max - loc)
  933.                     else
  934.                         slope := 1000.0;
  935.                     if slope > 0.0 then begin
  936.                             ColorStart := round(center - 127.5 / slope);
  937.                             ColorEnd := round(center + 127.5 / slope);
  938.                         end
  939.                     else begin
  940.                             ColorStart := round(center - MaxColor);
  941.                             ColorEnd := round(center + MaxColor);
  942.                         end;
  943.                     if ColorEnd < 0 then
  944.                         ColorEnd := 0;
  945.                     if ColorStart > 255 then
  946.                         ColorStart := 255;
  947.                     UpdateLUT;
  948.                     UpdateMap;
  949.                     ShowLUTValues(ColorStart, ColorEnd);
  950.                 until not button;
  951.                 IdentityFunction := false;
  952.             end; {with}
  953.     end;
  954.  
  955.  
  956.     procedure ConvertMouseToXY (p: point; var x, y: integer);
  957.     begin
  958.         x := (p.h - gmRectLeft) * 4;
  959.         if x < 0 then
  960.             x := 0;
  961.         if x > 255 then
  962.             x := 255;
  963.         y := (gmRectBottom - p.v) * 4;
  964.         if y < 0 then
  965.             y := 0;
  966.         if y > 255 then
  967.             y := 255;
  968.     end;
  969.  
  970.  
  971.     procedure DoFreehandEditing;
  972.         var
  973.             p: point;
  974.             x1, x2, y, i: integer;
  975.             FirstTime: boolean;
  976.     begin
  977.         with info^ do begin
  978.                 LUTMode := CustomGrayscale;
  979.                 SetPort(MapWindow);
  980.                 FirstTime := true;
  981.                 while button do begin
  982.                         x1 := x2;
  983.                         GetMouse(p);
  984.                         ConvertMouseToXY(p, x2, y);
  985.                         if x2 > 252 then
  986.                             x2 := 252;
  987.                         if FirstTime then begin
  988.                                 x1 := x2;
  989.                                 FirstTime := false;
  990.                             end;
  991.                         if x2 >= x1 then
  992.                             for i := x1 to x2 + 3 do
  993.                                 with cTable[i].rgb do begin
  994.                                         red := bsl(255 - y, 8);
  995.                                         green := bsl(255 - y, 8);
  996.                                         blue := bsl(255 - y, 8);
  997.                                     end
  998.                         else
  999.                             for i := x1 + 3 downto x2 do
  1000.                                 with cTable[i].rgb do begin
  1001.                                         red := bsl(255 - y, 8);
  1002.                                         green := bsl(255 - y, 8);
  1003.                                         blue := bsl(255 - y, 8);
  1004.                                     end;
  1005.                         DrawMap;
  1006.                         LoadLUT(cTable);
  1007.                         if ScreenDepth <> 8 then UpdatePicWindow;
  1008.                     end;
  1009.                 if not isGrayscaleLut then
  1010.                     LutMode := ColorLut;
  1011.             end;
  1012.     end;
  1013.  
  1014.  
  1015.     procedure DisableThresholding;
  1016.     begin
  1017.         with info^ do
  1018.             if thresholding then begin
  1019.                 ColorStart := SaveColorStart;
  1020.                 ColorEnd := SaveColorEnd;
  1021.                 FillColor1 := SaveFill1;
  1022.                 FillColor2 := SaveFill2;
  1023.                 UpdateLut;
  1024.                 UpdateMap;
  1025.                 Thresholding := false;
  1026.             end;
  1027.     end;
  1028.  
  1029.  
  1030.     procedure EnableThresholding (level: integer);
  1031.     begin
  1032.         with info^ do begin
  1033.             if not thresholding then begin
  1034.                 SaveColorStart := ColorStart;
  1035.                 SaveColorEnd := ColorEnd;
  1036.                 SaveFill1 := FillColor1;
  1037.                 SaveFill2 := FillColor2;
  1038.             end;
  1039.             ColorStart := level;
  1040.             ColorEnd := level;
  1041.             FillColor1 := WhiteRGB;
  1042.             FillColor2 := BlackRGB;
  1043.             UpdateLut;
  1044.             UpdateMap;
  1045.             Thresholding := true;
  1046.             if not macro then
  1047.                 SelectLutTool;
  1048.         end;
  1049.     end;
  1050.  
  1051.  
  1052.     procedure ResetMap;
  1053.     begin
  1054.         with info^ do begin
  1055.                 ColorStart := 0;
  1056.                 ColorEnd := 255;
  1057.                 if Thresholding then begin
  1058.                         FillColor1 := SaveFill1;
  1059.                         FillColor2 := SaveFill2;
  1060.                     end;
  1061.                 IdentityFunction := LutMode = Grayscale;
  1062.                 UpdateLUT;
  1063.                 UpdateMap;
  1064.             end;
  1065.     end;
  1066.  
  1067.  
  1068.     procedure DoMouseDownInMap;
  1069.         var
  1070.             r: rect;
  1071.             x, y, p1Dist, p2Dist: integer;
  1072.             mode: (StartPoint, EndPoint, Brightness, AdjustThreshold);
  1073.             p: point;
  1074.             pressed: boolean;
  1075.             x1, y1, x2, y2: integer;
  1076.             xintercept: integer;
  1077.             deltax, deltay, width: LongInt;
  1078.  
  1079.         procedure DoFixup;
  1080.         begin
  1081.             with info^ do
  1082.                 if ((x1 = 0) and (x2 = 0)) or ((x1 = 255) and (x2 = 255)) then begin
  1083.                         y1 := 0;
  1084.                         y2 := 255;
  1085.                     end;
  1086.         end;
  1087.  
  1088.     begin
  1089.         with info^ do begin
  1090.                 DisableDensitySlice;
  1091.                 if OptionKeyDown then begin
  1092.                         DoFreehandEditing;
  1093.                         exit(DoMouseDownInMap);
  1094.                     end;
  1095.                 if LUTMode = CustomGrayscale then
  1096.                     ResetGrayMap;
  1097.                 FindPoints(x1, y1, x2, y2);
  1098.                 SetPort(MapWindow);
  1099.                 GetMouse(p);
  1100.                 if PtInRect(p, gmIcon1) then begin
  1101.                         InvertRect(gmIcon1);
  1102.                         pressed := true;
  1103.                         while Button and pressed do begin
  1104.                                 GetMouse(p);
  1105.                                 if not PtInRect(p, gmIcon1) then begin
  1106.                                         InvertRect(gmIcon1);
  1107.                                         pressed := false;
  1108.                                     end;
  1109.                             end;
  1110.                         repeat
  1111.                         until not button;
  1112.                         if pressed then begin
  1113.                                 InvertRect(gmIcon1);
  1114.                                 ResetMap;
  1115.                                 exit(DoMouseDownInMap)
  1116.                             end;
  1117.                     end;
  1118.                 if PtInRect(p, gmIcon2) then begin
  1119.                         InvertRect(gmIcon2);
  1120.                         pressed := true;
  1121.                         while Button and pressed do begin
  1122.                                 GetMouse(p);
  1123.                                 if not PtInRect(p, gmIcon2) then begin
  1124.                                         InvertRect(gmIcon2);
  1125.                                         pressed := false;
  1126.                                     end;
  1127.                             end;
  1128.                         repeat
  1129.                         until not button;
  1130.                         if pressed then begin
  1131.                                 InvertRect(gmIcon2);
  1132.                                 if Thresholding then
  1133.                                     DisableThresholding
  1134.                                 else
  1135.                                     EnableThresholding(128);
  1136.                                 exit(DoMouseDownInMap)
  1137.                             end;
  1138.                     end;
  1139.                 if PtInRect(p, gmSlide1) then
  1140.                     AdjustBrightness;
  1141.                 if PtInRect(p, gmSlide2) then
  1142.                     AdjustContrast;
  1143.                 if p.v > (gmRectBottom + 4) then begin
  1144.                         if not thresholding and ((x2 - x1) <= 1) then begin
  1145.                                 thresholding := true;
  1146.                                 SaveFill1 := FillColor1;
  1147.                                 SaveFill2 := FillColor2;
  1148.                             end;
  1149.                         exit(DoMouseDownInMap);
  1150.                     end;
  1151.                 if LutMode = CustomGrayscale then
  1152.                     LutMode := Grayscale;
  1153.                 GetMouse(p);
  1154.                 ConvertMouseToXY(p, x, y);
  1155.                 if (x <= 24) or (y <= 32) then
  1156.                     mode := StartPoint
  1157.                 else if (x >= 224) or (y >= 232) then
  1158.                     mode := EndPoint
  1159.                 else if thresholding then
  1160.                     mode := AdjustThreshold
  1161.                 else
  1162.                     mode := brightness;
  1163.                 if mode = AdjustThreshold then
  1164.                     DrawLabels('Thresh:', '', '')
  1165.                 else
  1166.                     ShowLabels;
  1167.                 repeat
  1168.                     case mode of
  1169.                         StartPoint:  begin
  1170.                                 if thresholding then begin
  1171.                                         FillColor1 := SaveFill1;
  1172.                                         FillColor2 := SaveFill2;
  1173.                                     end;
  1174.                                 if x > y then
  1175.                                     y := 0
  1176.                                 else
  1177.                                     x := 0;
  1178.                                 x1 := x;
  1179.                                 if x1 > x2 then
  1180.                                     x2 := x1;
  1181.                                 y1 := y;
  1182.                                 if y1 > y2 then
  1183.                                     y2 := y1;
  1184.                                 DoFixUp;
  1185.                             end;
  1186.                         EndPoint:  begin
  1187.                                 if thresholding then begin
  1188.                                         FillColor1 := SaveFill1;
  1189.                                         FillColor2 := SaveFill2;
  1190.                                     end;
  1191.                                 if x > y then
  1192.                                     x := 255
  1193.                                 else
  1194.                                     y := 255;
  1195.                                 x2 := x;
  1196.                                 if x2 < x1 then
  1197.                                     x1 := x2;
  1198.                                 y2 := y;
  1199.                                 if y2 < y1 then
  1200.                                     y1 := y2;
  1201.                                 DoFixUp;
  1202.                             end;
  1203.                         Brightness:  begin
  1204.                                 deltax := x2 - x1;
  1205.                                 deltay := y2 - y1;
  1206.                                 if deltax = 0 then begin
  1207.                                         x1 := x;
  1208.                                         y1 := 0;
  1209.                                         x2 := x;
  1210.                                         y2 := 255;
  1211.                                     end
  1212.                                 else if deltay = 0 then begin
  1213.                                         x1 := 0;
  1214.                                         y1 := y;
  1215.                                         x2 := 255;
  1216.                                         y2 := y;
  1217.                                     end
  1218.                                 else begin
  1219.                                         x1 := x - y * deltax div deltay;
  1220.                                         xIntercept := x1;
  1221.                                         y1 := 0;
  1222.                                         if x1 < 0 then begin
  1223.                                                 y1 := -deltay * x1 div deltaX;
  1224.                                                 x1 := 0;
  1225.                                             end;
  1226.                                         y2 := 255;
  1227.                                         x2 := 255 * deltax div deltay;
  1228.                                         if xIntercept < 0 then
  1229.                                             x2 := x2 + xIntercept
  1230.                                         else
  1231.                                             x2 := x2 + x1;
  1232.                                         if x2 > 255 then begin
  1233.                                                 y2 := 255 - (x2 - 255) * deltay div deltax;
  1234.                                                 x2 := 255;
  1235.                                             end;
  1236.                                     end;
  1237.                                 if x2 < 1 then
  1238.                                     x2 := 1;
  1239.                                 if y2 < 1 then
  1240.                                     y2 := 1;
  1241.                                 if x1 > 254 then
  1242.                                     x1 := 254;
  1243.                                 if y1 > 254 then
  1244.                                     y1 := 254;
  1245.                             end;
  1246.                         AdjustThreshold:  begin
  1247.                                 x1 := x;
  1248.                                 y1 := 0;
  1249.                                 x2 := x;
  1250.                                 y2 := 255;
  1251.                             end;
  1252.                     end; {case}
  1253. {showmessage(concat(long2str(x1), '  ', long2str(y1), '  ', long2str(x2), '  ', long2str(y2), crStr, long2str(ColorStart), '  ', long2str(ColorEnd)));}
  1254.                     width := x2 - x1;
  1255.                     if y1 = 0 then
  1256.                         ColorStart := x1
  1257.                     else begin
  1258.                             if (y2 > y1) then
  1259.                                 ColorStart := -width * y1 div (y2 - y1)
  1260.                             else
  1261.                                 ColorStart := -MaxColor;
  1262.                         end;
  1263.                     if y2 = 255 then
  1264.                         ColorEnd := x2
  1265.                     else begin
  1266.                             if (y2 > y1) then
  1267.                                 ColorEnd := 255 + width * (255 - y2) div ((y2 - y1))
  1268.                             else
  1269.                                 ColorEnd := MaxColor;
  1270.                         end;
  1271.                     UpdateLUT;
  1272.                     UpdateMap;
  1273.                     if thresholding then
  1274.                         Show1Value(ColorStart, NoValue)
  1275.                     else
  1276.                         ShowLUTValues(ColorStart, ColorEnd);
  1277.                     GetMouse(p);
  1278.                     ConvertMouseToXY(p, x, y);
  1279.                 until not Button;
  1280.                 IdentityFunction := false;
  1281.                 if not thresholding and ((x2 - x1) <= 1) then begin
  1282.                         thresholding := true;
  1283.                         SaveFill1 := FillColor1;
  1284.                         SaveFill2 := FillColor2;
  1285.                     end;
  1286.             end; {with info}
  1287.     end;
  1288.  
  1289.  
  1290.     procedure DrawLUT;
  1291.         var
  1292.             tPort: GrafPtr;
  1293.             h, v, i: integer;
  1294.     begin
  1295.         GetPort(tPort);
  1296.         SetPort(LUTWindow);
  1297.         with LutWindow^ do begin
  1298.                 for v := 0 to 255 do begin
  1299.                         SetFColor(v);
  1300.                         MoveTo(0, v);
  1301.                         LineTo(cwidth, v)
  1302.                     end;
  1303.                 for i := 1 to nExtraColors + 2 do begin
  1304.                         SetFColor(ExtraColorsEntry[i]);
  1305.                         PaintRect(ExtraColorsRect[i]);
  1306.                     end;
  1307.                 TextFont(Geneva);
  1308.                 TextSize(9);
  1309.                 with ExtraColorsRect[1] do
  1310.                     MoveTo(left + 3, bottom - 1);
  1311.                 SetFColor(BlackIndex);
  1312.                 DrawString('white');
  1313.                 with ExtraColorsRect[2] do
  1314.                     MoveTo(left + 4, bottom - 1);
  1315.                 InvertRect(ExtraColorsRect[2]);
  1316.                 DrawString('black');
  1317.                 InvertRect(ExtraColorsRect[2]);
  1318.             end;
  1319.         SetPort(tPort);
  1320.     end;
  1321.  
  1322.  
  1323.     function LoadPP2Palette: boolean;
  1324. {Loads COLR resource from PixelPaint 2.0 palette file.}
  1325.         var
  1326.             i: integer;
  1327.             size: LongInt;
  1328.             h: Handle;
  1329.             PPColorTable: record
  1330.                     ctSize: INTEGER;
  1331.                     table: array[0..255] of RGBColor;
  1332.                 end;
  1333.     begin
  1334.         h := GetResource('COLR', 999);
  1335.         size := GetHandleSize(handle(h));
  1336.         if (ResError = NoErr) and (size = 1538) then
  1337.             with info^ do begin
  1338.                     BlockMove(handle(h)^, @PPColorTable, SizeOf(PPColorTable));
  1339.                     with PPColorTable do begin
  1340.                             for i := 0 to 255 do
  1341.                                 cTable[i].rgb := table[i];
  1342.                         end;
  1343.                     LoadLUT(cTable);
  1344.                     LutMode := ColorLut;
  1345.                     SetupPseudocolor;
  1346.                     IdentityFunction := false;
  1347.                     LoadPP2Palette := true;
  1348.                 end
  1349.         else
  1350.             LoadPP2Palette := false;
  1351.         if h <> nil then
  1352.             DisposeHandle(h);
  1353.     end;
  1354.  
  1355.  
  1356.     procedure LoadColorTable (theColorTable: CTabHandle);
  1357.         const
  1358.             ExpectedSize = 2056;
  1359.         var
  1360.             size: LongInt;
  1361.             MyColorTable: record
  1362.                     ctSeed: LONGINT;
  1363.                     transIndex: INTEGER;
  1364.                     ctSize: INTEGER;
  1365.                     ctTable: MyCSpecArray;
  1366.                 end;
  1367.     begin
  1368.         size := GetHandleSize(handle(theColorTable));
  1369.         if size < ExpectedSize then
  1370.             exit(LoadColorTable);
  1371.         if size > ExpectedSize then
  1372.             Size := ExpectedSize;
  1373.         BlockMove(handle(theColorTable)^, @MyColorTable, size);
  1374.         LoadLUT(MyColorTable.ctTable);
  1375.         with info^ do begin
  1376.                 cTable := MyColorTable.ctTable;
  1377.                 LutMode := ColorLut;
  1378.                 IdentityFunction := false;
  1379.             end;
  1380.         SetupPseudocolor;
  1381.     end;
  1382.  
  1383.  
  1384.     function LoadCLUTResource;{(id:integer):boolean}
  1385.         const
  1386.             ExpectedSize = 2056;
  1387.         var
  1388.             Size: LongInt;
  1389.             h: cTabHandle;
  1390.     begin
  1391.         DisableDensitySlice;
  1392.         h := GetCTable(id);
  1393.         size := GetHandleSize(handle(h));
  1394.         if (ResError <> NoErr) or (size < ExpectedSize) then begin
  1395.                 LoadCLUTResource := false;
  1396.                 if id = PixelpaintID then begin
  1397.                         if LoadPP2Palette then
  1398.                             LoadCLUTResource := true;
  1399.                     end;
  1400.                 if h <> nil then
  1401.                     DisposeCTable(h);
  1402.                 exit(LoadCLUTResource)
  1403.             end;
  1404.         LoadColorTable(h);
  1405.         DisposeCTable(h);
  1406.         LoadCLUTResource := true;
  1407.     end;
  1408.  
  1409.  
  1410.     procedure GetLookupTable;{(VAR table:LookupTable)}
  1411.         var
  1412.             i, r, g, b: integer;
  1413.             GrayscaleImage: boolean;
  1414.     begin
  1415.         with info^ do begin
  1416.                 if DensitySlicing then begin
  1417.                         for i := 0 to 255 do
  1418.                             if (i >= SliceStart) and (i <= SliceEnd) then begin
  1419.                                     if ThresholdToForeground then
  1420.                                         table[i] := ForegroundIndex
  1421.                                     else
  1422.                                         table[i] := i
  1423.                                 end
  1424.                             else begin
  1425.                                     if NonThresholdToBackground then
  1426.                                         table[i] := BackgroundIndex
  1427.                                     else
  1428.                                         table[i] := i
  1429.                                 end;
  1430.                         DisableDensitySlice;
  1431.                         exit(GetLookupTable);
  1432.                     end;
  1433.                 if (LutMode = GrayScale) or (LutMode = CustomGrayscale) then
  1434.                     for i := 0 to 255 do
  1435.                         table[i] := 255 - BSR(cTable[i].RGB.red, 8)
  1436.                 else begin
  1437.                         table[0] := 0;
  1438.                         for i := 1 to 254 do
  1439.                             with cTable[i].RGB do
  1440.                                 table[i] := 255 - trunc(band(bsr(red, 8), 255) * 0.3 + band(bsr(green, 8), 255) * 0.59 + band(bsr(blue, 8), 255) * 0.11);
  1441.                         table[255] := 255;
  1442.                     end;
  1443.             end; {with}
  1444.     end;
  1445.  
  1446.  
  1447.     procedure RedrawLUTWindow;
  1448.     begin
  1449.         LoadLUT(info^.cTable);
  1450.         cheight := 256 + (2 + nExtraColors) * ExtraColorsHeight;
  1451.         SizeWindow(LUTWindow, cwidth, cheight, true);
  1452.     end;
  1453.  
  1454.  
  1455.     procedure DrawDensitySlice (OptionKey: boolean);
  1456.         var
  1457.             i, tRed: integer;
  1458.     begin
  1459.         with info^ do begin
  1460.                 if OptionKey then begin
  1461.                         UndoLutChange;
  1462.                         exit(DrawDensitySlice);
  1463.                     end
  1464.                 else
  1465.                     for i := 0 to 255 do
  1466.                         if (i >= SliceStart) and (i <= SliceEnd) then
  1467.                             cTable[i].rgb := SliceColor
  1468.                         else
  1469.                             ctable[i].rgb := UndoInfo^.cTable[i].rgb;
  1470.                 LoadLUT(cTable);
  1471.                 if ScreenDepth <> 8 then begin
  1472.                         if ScreenDepth > 2 then
  1473.                             DrawLut;
  1474.                         UpdatePicWindow;
  1475.                     end;
  1476.             end;
  1477.     end;
  1478.  
  1479.  
  1480.     procedure SelectLutTool;
  1481.         var
  1482.             tPort: GrafPtr;
  1483.     begin
  1484.         if (CurrentTool <> LutTool) and (CurrentTool <> Wand) then begin
  1485.                 GetPort(tPort);
  1486.                 SetPort(ToolWindow);
  1487.                 InvalRect(ToolRect[CurrentTool]);
  1488.                 InvalRect(ToolRect[LutTool]);
  1489.                 CurrentTool := LutTool;
  1490.                 isSelectionTool := false;
  1491.                 SetPort(tPort);
  1492.             end;
  1493.     end;
  1494.  
  1495.  
  1496.     procedure EnableDensitySlice;
  1497.     begin
  1498.         if not DensitySlicing then begin
  1499.                 SetupLutUndo;
  1500.                 DrawDensitySlice(false);
  1501.                 DensitySlicing := true;
  1502.                 SelectLUTTool;
  1503.             end;
  1504.     end;
  1505.  
  1506.  
  1507.     procedure DoImportLut (fname: str255; vnum: integer);
  1508.         var
  1509.             err: OSErr;
  1510.             f, i,j,tRed: integer;
  1511.             ByteCount: LongInt;
  1512.             ImportedLUT: array[1..3] of packed array[0..255] of byte;
  1513.     begin
  1514.         DisableDensitySlice;
  1515.         err := fsopen(fname, vNum, f);
  1516.         ByteCount := 768;
  1517.         err := fsRead(f, ByteCount, @ImportedLUT);
  1518.         if err = NoErr then
  1519.             with info^ do begin
  1520.                     for i := 0 to 255 do
  1521.                         with cTable[i], cTable[i].rgb do begin
  1522.                                 value := 0;
  1523.                                 red := bsl(band(ImportedLUT[1, i],255), 8);
  1524.                                 green := bsl(band(ImportedLUT[2, i],255), 8);
  1525.                                 blue := bsl(band(ImportedLUT[3, i],255), 8);
  1526.                             end;
  1527.                     LoadLUT(cTable);
  1528.                     SetupPseudocolor;
  1529.                     LutMode := PseudoColor;
  1530.                     IdentityFunction := false;
  1531.                     if isGrayScaleLUT then
  1532.                         info^.LutMode := CustomGrayScale;
  1533.                     UpdateMap;
  1534.                 end
  1535.         else
  1536.             beep;
  1537.         err := fsClose(f);
  1538.     end;
  1539.  
  1540.  
  1541.     procedure OpenOldPalette (fname: str255; RefNum: integer);
  1542. {Opens palette files created by versions NIH Image earlier than 1.42.}
  1543.         var
  1544.             PaletteHeader: ColorArray;
  1545.             err, f, ColorWidth: integer;
  1546.             size: LongInt;
  1547.     begin
  1548.         DisableDensitySlice;
  1549.         err := fsopen(fname, RefNum, f);
  1550.         with info^ do begin
  1551.                 size := SizeOf(ColorArray);
  1552.                 err := fsread(f, size, @PaletteHeader);
  1553.                 nColors := PaletteHeader[0];
  1554.                 if nColors > MaxPseudocolors then
  1555.                     nColors := MaxPseudoColors;
  1556.                 ColorEnd := 255 - PaletteHeader[1];
  1557.                 ColorWidth := PaletteHeader[2];
  1558.                 ColorStart := ColorEnd - nColors * ColorWidth + 1;
  1559.                 if ColorStart < 0 then
  1560.                     ColorStart := 0;
  1561.                 FillColor1 := BlackRGB;
  1562.                 FillColor2 := BlackRGB;
  1563.                 err := fsread(f, size, @RedLut);
  1564.                 err := fsread(f, size, @GreenLut);
  1565.                 err := fsread(f, size, @BlueLut);
  1566.                 LutMode := PseudoColor;
  1567.                 InvertedColorTable := false;
  1568.             end;
  1569.         err := fsclose(f);
  1570.         UpdateLUT;
  1571.     end;
  1572.  
  1573.  
  1574.     procedure OpenNewPalette (fname: str255; RefNum: integer);
  1575. {Opens palette files created by versions of NIH Image later than 1.41.}
  1576.         var
  1577.             err, f: integer;
  1578.             count: LongInt;
  1579.             hdr: PaletteHeader;
  1580.     begin
  1581.         DisableDensitySlice;
  1582.         err := fsopen(fname, RefNum, f);
  1583.         with info^ do begin
  1584.                 count := SizeOf(PaletteHeader);
  1585.                 err := fsread(f, count, @hdr);
  1586.                 with hdr do begin
  1587.                         nColors := pnColors;
  1588.                         if nColors > 256 then
  1589.                             nColors := 256;
  1590.                         ColorStart := pColorStart;
  1591.                         ColorEnd := pColorEnd;
  1592.                         FillColor1 := pFill1;
  1593.                         FillColor2 := pFill2;
  1594.                         InvertedColorTable := false;
  1595.                     end;
  1596.                 count := nColors;
  1597.                 err := fsread(f, count, @RedLut);
  1598.                 count := nColors;
  1599.                 err := fsread(f, count, @GreenLut);
  1600.                 count := nColors;
  1601.                 err := fsread(f, count, @BlueLut);
  1602.                 LutMode := PseudoColor;
  1603.             end;
  1604.         err := fsclose(f);
  1605.         UpdateLUT;
  1606.     end;
  1607.  
  1608.  
  1609.     procedure OpenColorTable (fname: str255; RefNum: integer);
  1610.         var
  1611.             err: OSErr;
  1612.             f: integer;
  1613.             FileSize, count: LongInt;
  1614.             id: packed array[1..4] of char;
  1615.     begin
  1616.         err := fsopen(fname, RefNum, f);
  1617.         err := GetEOF(f, FileSize);
  1618.         count := SizeOf(id);
  1619.         err := fsread(f, count, @id);
  1620.         err := fsclose(f);
  1621.         if FileSize = 768 then
  1622.             DoImportLut(fname, RefNum)
  1623.         else if id = 'ICOL' then
  1624.             OpenNewPalette(fname, RefNum)
  1625.         else
  1626.             OpenOldPalette(fname, RefNum);
  1627.     end;
  1628.  
  1629.  
  1630.     procedure ImportPalette (FileType: OSType; fname: str255; vnum: integer);
  1631.         var
  1632.             RefNum: integer;
  1633.             ok: boolean;
  1634.             err: OSErr;
  1635.     begin
  1636.         err := SetVol(nil, vnum);
  1637.         refNum := OpenResFile(fname);
  1638.         if RefNum <> -1 then begin
  1639.                 if FileType = 'CLUT' then
  1640.                     ok := LoadClutResource(KlutzID)
  1641.                 else
  1642.                     ok := LoadClutResource(PixelPaintID); {Load PixelPaint or Canvas palette}
  1643.                 CloseResFile(RefNum);
  1644.                 if isGrayScaleLUT then begin
  1645.                         info^.LutMode := CustomGrayScale;
  1646.                         DrawMap;
  1647.                     end;
  1648.             end;
  1649.     end;
  1650.  
  1651.  
  1652.     procedure InitPaletteHeader (var hdr: PaletteHeader);
  1653.         var
  1654.             i: integer;
  1655.     begin
  1656.         with hdr, info^ do begin
  1657.                 pID := 'ICOL';
  1658.                 pVersion := version;
  1659.                 pnColors := nColors;
  1660.                 pColorStart := ColorStart;
  1661.                 pColorEnd := ColorEnd;
  1662.                 pFill1 := FillColor1;
  1663.                 pFill2 := FillColor2;
  1664.                 for i := 1 to 4 do
  1665.                     pUnused[i] := 0;
  1666.             end;
  1667.     end;
  1668.  
  1669.  
  1670.     procedure SaveLutResource;
  1671. {Saves the current color table as  a CPAL resource}
  1672.         var
  1673.             id: integer;
  1674.             canceled: boolean;
  1675.             PalH: handle;
  1676.             hdr: PaletteHeader;
  1677.             p: ptr;
  1678.     begin
  1679.         with info^ do begin
  1680.                 id := GetInt('Resource ID', 1000, canceled);
  1681.                 if canceled then
  1682.                     exit(SaveLutResource);
  1683.                 PalH := GetResource('CPAL', id);
  1684.                 if GetHandleSize(PalH) > 0 then begin
  1685.                         RemoveResource(PalH);
  1686.                         DisposeHandle(PalH);
  1687.                     end;
  1688.                 InitPaletteHeader(hdr);
  1689.                 PalH := NewHandle(SizeOF(PaletteHeader) + nColors * 3);
  1690.                 p := PalH^;
  1691.                 BlockMove(@hdr, p, SizeOf(PaletteHeader));
  1692.                 p := ptr(ord4(p) + SizeOf(PaletteHeader));
  1693.                 BlockMove(@RedLut, p, nColors);
  1694.                 p := ptr(ord4(p) + nColors);
  1695.                 BlockMove(@GreenLut, p, nColors);
  1696.                 p := ptr(ord4(p) + nColors);
  1697.                 BlockMove(@BlueLut, p, nColors);
  1698.                 AddResource(PalH, 'CPAL', id, '');
  1699.                 WriteResource(PalH);
  1700.                 if ResError <> NoErr then
  1701.                     beep;
  1702.                 DisposeHandle(PalH);
  1703.             end;
  1704.     end;
  1705.  
  1706.  
  1707.     procedure GetLutResource (id: integer);
  1708.         var
  1709.             LutH: handle;
  1710.             hdr: PaletteHEader;
  1711.             p: ptr;
  1712.     begin
  1713.         with info^ do begin
  1714.                 LutH := GetResource('CPAL', id);
  1715.                 if (ResError <> noErr) or (LutH = nil) then begin
  1716.                         beep;
  1717.                         if LutH <> nil then
  1718.                             ReleaseResource(LutH);
  1719.                         exit(GetLutResource)
  1720.                     end;
  1721.                 p := LutH^;
  1722.                 BlockMove(p, @hdr, SizeOf(PaletteHeader));
  1723.                 with hdr do begin
  1724.                         if pID <> 'ICOL' then begin
  1725.                                 beep;
  1726.                                 ReleaseResource(LutH);
  1727.                                 exit(GetLutResource);
  1728.                             end;
  1729.                         nColors := pnColors;
  1730.                         if nColors > 256 then
  1731.                             nColors := 256;
  1732.                         ColorStart := pColorStart;
  1733.                         ColorEnd := pColorEnd;
  1734.                         FillColor1 := pFill1;
  1735.                         FillColor2 := pFill2;
  1736.                         InvertedColorTable := false;
  1737.                     end;
  1738.                 p := ptr(ord4(p) + SizeOf(PaletteHeader));
  1739.                 BlockMove(p, @RedLut, nColors);
  1740.                 p := ptr(ord4(p) + nColors);
  1741.                 BlockMove(p, @GreenLut, nColors);
  1742.                 p := ptr(ord4(p) + nColors);
  1743.                 BlockMove(p, @BlueLut, nColors);
  1744.                 ReleaseResource(LutH);
  1745.             end;
  1746.     end;
  1747.  
  1748.  
  1749.     procedure DrawScale;
  1750.         var
  1751.             hloc, vloc, width, height, SaveForeground, LUTStart, LutEnd, LUTWidth: integer;
  1752.             SaveGDevice: GDHandle;
  1753.     begin
  1754.         if NoSelection or NotRectangular then
  1755.             exit(DrawScale);
  1756.         ShowWatch;
  1757.         with info^.RoiRect, info^ do begin
  1758.                 width := right - left;
  1759.                 height := bottom - top;
  1760.                 if (width = 0) or (height = 0) then
  1761.                     exit(DrawScale);
  1762.                 SaveGDevice := GetGDevice;
  1763.                 SetGDevice(osGDevice);
  1764.                 SetPort(GrafPtr(osPort));
  1765.                 PenNormal;
  1766.                 SetupUndoFromClip;
  1767.                 SetupUndo;
  1768.                 WhatToUndo := UndoEdit;
  1769.                 SaveForeground := ForegroundIndex;
  1770.                 LUTStart := ColorStart;
  1771.                 if LutStart <= 0 then
  1772.                     LutStart := 1;
  1773.                 LutEnd := ColorEnd;
  1774.                 if LutEnd >= 255 then
  1775.                     LutEnd := 254;
  1776.                 LUTWidth := LutEnd - LutStart + 1;
  1777.                 if width >= height then
  1778.                     for hloc := left to right - 1 do begin
  1779.                             SetForegroundColor(trunc(((hloc - left) / width) * LUTWidth) + LUTStart);
  1780.                             MoveTo(hloc, top);
  1781.                             LineTo(hloc, Bottom - 1);
  1782.                         end
  1783.                 else
  1784.                     for vloc := top to bottom - 1 do begin
  1785.                             SetForegroundColor(trunc(((vloc - top) / height) * LUTWidth) + LUTStart);
  1786.                             MoveTo(left, vloc);
  1787.                             LineTo(right - 1, vloc);
  1788.                         end;
  1789.                 SetForegroundColor(SaveForeground);
  1790.                 changes := true;
  1791.             end;
  1792.         SetupRoiRect;
  1793.         SetGDevice(SaveGDevice);
  1794.     end;
  1795.  
  1796.  
  1797.     procedure MakeSpectrum;
  1798.   {Generates the "Spectrum" color table.}
  1799.         const
  1800.             Sat = -1;
  1801.             Val = -1;
  1802.         var
  1803.             i: integer;
  1804.             color: HSVColor;
  1805.     begin
  1806.         with info^ do begin
  1807.                 for i := 0 to 255 do begin
  1808.                         color.hue := i * 256;
  1809.                         color.saturation := sat;
  1810.                         color.value := val;
  1811.                         HSV2RGB(color, ctable[i].rgb);
  1812.                     end;
  1813.                 LutMode := ColorLut;
  1814.                 IdentityFunction := false;
  1815.                 SetupPseudocolor;
  1816.             end;
  1817.     end;
  1818.  
  1819.  
  1820.     function GetColorTableItem (ctab: ColorTableType): integer;
  1821.     begin
  1822.         case ctab of
  1823.             AppleDefault: 
  1824.                 GetColorTableItem := SystemPaletteItem;
  1825.             Pseudo20: 
  1826.                 GetColorTableItem := Pseudo20Item;
  1827.             Pseudo32: 
  1828.                 GetColorTableItem := Pseudo32Item;
  1829.             Rainbow: 
  1830.                 GetColorTableItem := RainbowItem;
  1831.             Fire1: 
  1832.                 GetColorTableItem := Fire1Item;
  1833.             Fire2: 
  1834.                 GetColorTableItem := Fire2Item;
  1835.             Ice: 
  1836.                 GetColorTableItem := IceItem;
  1837.             Grays: 
  1838.                 GetColorTableItem := GraysItem;
  1839.             Spectrum: 
  1840.                 GetColorTableItem := SpectrumItem;
  1841.             otherwise
  1842.                 GetColorTableItem := Pseudo20Item;
  1843.         end;
  1844.     end;
  1845.  
  1846.  
  1847.     procedure SwitchColorTables (item: integer; update: boolean);
  1848.         var
  1849.             ok: boolean;
  1850.     begin
  1851.         DisableDensitySlice;
  1852.         if update then
  1853.             SetupLutUndo;
  1854.         with info^ do begin
  1855.                 case item of
  1856.                     SystemPaletteItem:  begin
  1857.                             ok := LoadCLUTResource(AppleDefaultCLUT);
  1858.                             ColorTable := AppleDefault;
  1859.                         end;
  1860.                     Pseudo20Item:  begin
  1861.                             GetLutResource(Pseudo20ID);
  1862.                             ColorTable := Pseudo20;
  1863.                         end;
  1864.                     Pseudo32Item:  begin
  1865.                             GetLutResource(Pseudo32ID);
  1866.                             ColorTable := Pseudo32;
  1867.                         end;
  1868.                     RainbowItem:  begin
  1869.                             GetLutResource(RainbowID);
  1870.                             ColorTable := Rainbow;
  1871.                         end;
  1872.                     Fire1Item:  begin
  1873.                             GetLutResource(Fire1ID);
  1874.                             ColorTable := Fire1;
  1875.                         end;
  1876.                     Fire2Item:  begin
  1877.                             GetLutResource(Fire2ID);
  1878.                             ColorTable := Fire2;
  1879.                         end;
  1880.                     IceItem:  begin
  1881.                             GetLutResource(IceID);
  1882.                             ColorTable := Ice;
  1883.                         end;
  1884.                     GraysItem:  begin
  1885.                             GetLutResource(GraysID);
  1886.                             ColorTable := Grays;
  1887.                         end;
  1888.                     SpectrumItem: 
  1889.                         if ControlKeyDown and OptionKeyDown and ShiftKeyDown then
  1890.                             SaveLutResource
  1891.                         else begin
  1892.                                 MakeSpectrum;
  1893.                                 ColorTable := Spectrum;
  1894.                             end;
  1895.                 end; {case}
  1896.                 LutMode := Pseudocolor;
  1897.                 if update then begin
  1898.                         UpdateLUT;
  1899.                         UpdateMap;
  1900.                     end;
  1901.             end;
  1902.     end;
  1903.  
  1904.  
  1905.     procedure SetNumberOfColors (n: integer);
  1906.         var
  1907.             i, r, g, b, index: integer;
  1908.             eIndex, inc, fraction: extended;
  1909.             SaveRed, SaveGreen, SaveBlue: LutArray;
  1910.     begin
  1911.         with info^ do begin
  1912.                 SaveRed := RedLUT;
  1913.                 SaveGreen := GreenLUT;
  1914.                 SaveBlue := BlueLUT;
  1915.                 eIndex := 0.0;
  1916.                 inc := (nColors - 1) / (n - 1);
  1917.                 for i := 0 to n - 1 do begin
  1918.                         index := trunc(eIndex);
  1919.                         if index >= (nColors - 1) then begin
  1920.                                 RedLUT[i] := SaveRed[index];
  1921.                                 GreenLUT[i] := SaveGreen[index];
  1922.                                 BlueLUT[i] := SaveBlue[index]
  1923.                             end
  1924.                         else begin
  1925.                                 fraction := eIndex - index;
  1926.                                 RedLUT[i] := round(SaveRed[index] * (1.0 - fraction) + SaveRed[index + 1] * fraction);
  1927.                                 GreenLUT[i] := round(SaveGreen[index] * (1.0 - fraction) + SaveGreen[index + 1] * fraction);
  1928.                                 BlueLUT[i] := round(SaveBlue[index] * (1.0 - fraction) + SaveBlue[index + 1] * fraction);
  1929.                             end;
  1930.                         eIndex := eIndex + inc;
  1931.                     end;
  1932.                 nColors := n;
  1933.                 LutMode := PseudoColor;
  1934.                 ColorTable := CustomTable;
  1935.                 UpdateLUT;
  1936.                 UpdateMap;
  1937.             end;
  1938.     end;
  1939.  
  1940.  
  1941.     procedure SetNumberOfExtraColors;
  1942.         var
  1943.             n: integer;
  1944.             Canceled: boolean;
  1945.     begin
  1946.         n := GetInt('Number of Extra Colors(0..6):', nExtraColors, Canceled);
  1947.         if (n <= 6) and (n >= 0) and not Canceled then begin
  1948.                 nExtraColors := n;
  1949.                 RedrawLUTWindow;
  1950.                 SelectWindow(LUTWindow);
  1951.                 if info <> NoInfo then
  1952.                     SelectWindow(info^.wptr);
  1953.             end
  1954.         else if not Canceled then
  1955.             beep;
  1956.     end;
  1957.  
  1958.  
  1959.     procedure DoLutOptions;
  1960.         const
  1961.             nColorsID = 7;
  1962.             nExtraColorsID = 8;
  1963.             InvertID = 9;
  1964.         var
  1965.             mylog: DialogPtr;
  1966.             item, i, n, nExtra: integer;
  1967.             InvertLut: boolean;
  1968.     begin
  1969.         with info^ do begin
  1970.                 InitCursor;
  1971.                 mylog := GetNewDialog(210, nil, pointer(-1));
  1972.                 n := nColors;
  1973.                 SetDNum(MyLog, nColorsID, n);
  1974.                 nExtra := nExtraColors;
  1975.                 SetDNum(MyLog, nExtraColorsID, nExtra);
  1976.                 InvertLut := false;
  1977.                 SetDlogItem(mylog, InvertID, ord(InvertLut));
  1978.                 repeat
  1979.                     ModalDialog(nil, item);
  1980.                     if item = nColorsID then
  1981.                         n := GetDNum(MyLog, nColorsID);
  1982.                     if item = nExtraColorsID then
  1983.                         nExtra := GetDNum(MyLog, nExtraColorsID);
  1984.                     if item = InvertID then begin
  1985.                             InvertLut := not InvertLut;
  1986.                             SetDlogItem(mylog, InvertID, ord(InvertLut));
  1987.                         end;
  1988.                 until (item = ok) or (item = cancel);
  1989.                 DisposeDialog(mylog);
  1990.                 if item = cancel then
  1991.                     exit(DoLutOptions);
  1992.                 DisableDensitySlice;
  1993.                 SetupLutUndo;
  1994.                 if n < 1 then
  1995.                     n := 1;
  1996.                 if n > 256 then
  1997.                     n := 256;
  1998.                 if n <> nColors then
  1999.                     SetNumberOfColors(n);
  2000.                 if (nExtra <> nExtraColors) and (nExtra >= 0) and (nExtra <= 6) then begin
  2001.                         nExtraColors := nExtra;
  2002.                         RedrawLUTWindow;
  2003.                         SelectWindow(LUTWindow);
  2004.                         if info <> NoInfo then
  2005.                             SelectWindow(info^.wptr);
  2006.                     end;
  2007.                 if InvertLut then begin
  2008.                         InvertPalette;
  2009.                         UpdateLut;
  2010.                     end;
  2011.             end; {with info}
  2012.     end;
  2013.  
  2014.  
  2015.     function SetupMask: boolean;
  2016. {Creates a mask in the undo buffer for operating}
  2017. {on non-rectangular selections .}
  2018.         var
  2019.             tPort: GrafPtr;
  2020.             SaveInfo: InfoPtr;
  2021.             SaveGDevice: GDHandle;
  2022.     begin
  2023.         if NoUndo then begin
  2024.                 SetupMask := false;
  2025.                 exit(SetupMask)
  2026.             end;
  2027.         SetupUndoInfoRec;
  2028.         SaveInfo := Info;
  2029.         Info := UndoInfo;
  2030.         SaveGDevice := GetGDevice;
  2031.         SetGDevice(osGDevice);
  2032.         GetPort(tPort);
  2033.         with Info^ do begin
  2034.                 SetPort(GrafPtr(osPort));
  2035.                 pmForeColor(BlackIndex);
  2036.                 pmBackColor(WhiteIndex);
  2037.                 PenNormal;
  2038.                 EraseRect(RoiRect);
  2039.                 PaintRgn(roiRgn);
  2040.             end;
  2041.         SetPort(tPort);
  2042.         SetGDevice(SaveGDevice);
  2043.         Info := SaveInfo;
  2044.         SetupMask := true;
  2045.     end;
  2046.  
  2047.     procedure ApplyTableToLine (data: ptr; var table: LookupTable; width: LongInt);
  2048. {$IFC PowerPC}
  2049.     var
  2050.         line: LinePtr;
  2051.         i: integer;
  2052.     begin
  2053.         line := LinePtr(data);
  2054.         for i := 0 to width - 1 do
  2055.             Line^[i] := table[band(Line^[i],255)];
  2056.     end;
  2057. {$ELSEC}
  2058.  
  2059. {a0 = data}
  2060. {a1 = lookup table}
  2061. {d0 = width }
  2062. {d1 = pixel value}
  2063. inline
  2064.     $4E56, $0000, {  link a6,#0}
  2065.     $48E7, $C0C0, {  movem.l a0-a1/d0-d1,-(sp)}
  2066.     $206E, $000C, {  move.l 12(a6),a0}
  2067.     $226E, $0008, {  move.l 8(a6),a1}
  2068.     $202E, $0004, {  move.l 4(a6),d0}
  2069.     $5380,       {  subq.l #1,d0}
  2070.     $4281,       {  clr.l d1}
  2071.     $1210,       {L move.b (a0),d1}
  2072.     $10F1, $1000, {  move.b 0(a1,d1.w),(a0)+}
  2073.     $51C8, $FFF8, {  dbra d0,L}
  2074.     $4CDF, $0303, {  movem.l (sp)+,a0-a1/d0-d1}
  2075.     $4E5E,       {  unlk a6}
  2076.     $DEFC, $000C; {  add.w #12,sp}
  2077. {$ENDC}
  2078.  
  2079.  
  2080. procedure PutLineUsingMask (h, v, count: integer; var line: LineType);
  2081.     var
  2082.         aLine, MaskLine: LineType;
  2083.         i: integer;
  2084.         SaveInfo: InfoPtr;
  2085. begin
  2086.     if count > MaxLine then
  2087.         count := MaxLine;
  2088.     GetLine(h, v, count, aline);
  2089.     SaveInfo := Info;
  2090.     Info := UndoInfo;
  2091.     GetLine(h, v, count, MaskLine);
  2092.     for i := 0 to count - 1 do
  2093.         if MaskLine[i] = BlackIndex then
  2094.             aLine[i] := line[i];
  2095.     info := SaveInfo;
  2096.     PutLine(h, v, count, aLine);
  2097. end;
  2098.  
  2099.  
  2100. procedure ApplyTable(var table: LookupTable);
  2101.     var
  2102.         width, NumberOfLines, i, hloc, vloc: integer;
  2103.         offset: LongInt;
  2104.         p: ptr;
  2105.         UseMask: boolean;
  2106.         TempLine: LineType;
  2107.         AutoSelectAll: boolean;
  2108. begin
  2109.     if NotInBounds then
  2110.         exit(ApplyTable);
  2111.     AutoSelectAll := not Info^.RoiShowing;
  2112.     if AutoSelectAll then
  2113.         SelectAll(false);
  2114.     if TooWide then
  2115.         exit(ApplyTable);
  2116.     ShowWatch;
  2117.     with info^.RoiRect, info^ do begin
  2118.             if RoiType <> RectRoi then
  2119.                 UseMask := SetupMask
  2120.             else
  2121.                 UseMask := false;
  2122.             SetupUndoFromClip;
  2123.             WhatToUndo := UndoTransform;
  2124.             offset := top * BytesPerRow + left;
  2125.             if UseMask then
  2126.                 p := @TempLine
  2127.             else
  2128.                 p := ptr(ord4(PicBaseAddr) + offset);
  2129.             width := right - left;
  2130.             NumberOfLines := bottom - top;
  2131.             hloc := left;
  2132.             vloc := top;
  2133.         end;
  2134.     if width > 0 then
  2135.         for i := 1 to NumberOfLines do
  2136.             if UseMask then begin
  2137.                     GetLine(hloc, vloc, width, TempLine);
  2138.                     ApplyTableToLine(p, table, width);
  2139.                     PutLineUsingMask(hloc, vloc, width, TempLine);
  2140.                     vloc := vloc + 1
  2141.                 end
  2142.             else begin
  2143.                     ApplyTableToLine(p, table, width);
  2144.                     p := ptr(ord4(p) + info^.BytesPerRow);
  2145.                 end;
  2146.     with info^ do begin
  2147.             UpdateScreen(RoiRect);
  2148.             Info^.changes := true;
  2149.         end;
  2150.     SetupRoiRect;
  2151.     if AutoSelectAll then
  2152.         KillRoi;
  2153. end;
  2154.  
  2155.  
  2156. procedure FixColors;
  2157.     {Because NIH Image always sets LUT entries 0 and 255 to white and black respectively we need to map}
  2158.     {pixels with values of 0 or 255 to the nearest matching color in the other 254  LUT entries.}
  2159.     var
  2160.         i, match0, match255: integer;
  2161.         table: LookupTable;
  2162.  
  2163.     procedure BestMatch (index1: integer; var match: integer);
  2164.         var
  2165.             i, index2: integer;
  2166.             rdiff, gdiff, bdiff, r1, g1, b1: LongInt;
  2167.             diff, mindiff: extended;
  2168.     begin
  2169.         match := index1;
  2170.         mindiff := 10e10;
  2171.         if index1 = 0 then
  2172.             index2 := 1
  2173.         else
  2174.             index2 := 254;
  2175.         with info^ do begin
  2176.             r1:=band(bsr(cTable[index1].rgb.red, 8),255);
  2177.             g1:=band(bsr(cTable[index1].rgb.green, 8),255);
  2178.             b1:=band(bsr(cTable[index1].rgb.blue, 8),255);
  2179.             for i := 1 to 254 do begin
  2180.                     rdiff := r1 - band(bsr(cTable[index2].rgb.red, 8),255);
  2181.                     gdiff := g1 - band(bsr(cTable[index2].rgb.green, 8),255);
  2182.                     bdiff := b1 - band(bsr(cTable[index2].rgb.blue, 8),255);
  2183.                     diff := sqrt(sqr(rdiff) + sqr(gdiff) + sqr(bdiff));
  2184.                     if diff < mindiff then begin
  2185.                             match := index2;
  2186.                             mindiff := diff;
  2187.                         end;
  2188.                     if index1 = 0 then
  2189.                         index2 := index2 + 1
  2190.                     else
  2191.                         index2 := index2 - 1;
  2192.                 end; {for}
  2193.         end; {with}
  2194.     end;
  2195.  
  2196. begin
  2197.     BestMatch(0, match0);
  2198.     BestMatch(255, match255);
  2199.     table[0] := match0;
  2200.     for i := 1 to 254 do
  2201.         table[i] := i;
  2202.     table[255] := match255;
  2203.     ApplyTable(table);
  2204. end;
  2205.  
  2206.  
  2207. end.